%
% psfrag.sty:  LaTeX style file for overlaying postscript text in a postscript
%              file (included via \epsfbox or \special) with arbitrary
% 	       fragments of LaTeX.
%
% Requirements:
%
%   - The psfrag macros (currently) only work with LaTeX.
%
%   - You'll need the shell script ps2psfrag (which uses ghostscript from
%     the gnu distribution) and dvips (from Radical Eye Software, and
%     widely available at many TeX installations).  Other dvi to postscript
%     drivers will *not* work.  Do yourself a favor and get/use dvips.
%
% Usage:
%
%   - Include both the epsf and psfrag document style options.
%
%   - For each postscript file you should run the ps2psfrag shell script:
%
%           ps2psfrag example.ps
%
%     This uses ghostscript to generate the file example.psfrag (which
%     contains LaTeX source that describes all the postscript text that
%     example.ps places).  Since you'll need to run ps2psfrag every time
%     example.ps is modified, a makefile will save typing, eg:
%
%	# makefile for creating .psfrag files from .ps files
%	
%	.SUFFIXES: .ps .psfrag
%	
%	all:	example.psfrag another.psfrag andagain.psfrag
%	
%	.ps.psfrag:
%		ps2psfrag $*.ps
%
%   - There are two methods to replace postscript text with LaTeX fragments
%     (they can be mixed):
%
%     + Embedded (method 1): postscript text that looks like the macro
%
%	  \tex[posn][psposn][scale][rot]{LaTeX text}
%
%       is replaced by the LaTeX text in the argument.  The four optional
%       arguments are the same as for \psfrag and are explained below.
%
%	Example: in a drawing program like xfig, you place the text
%
%		\tex{$\alpha$}
%
%	at a particular point.  (Alignment is explained below.)
%
%	Note that if the text is too long it could affect the postscript
%	file's bounding box.  You should use method 2 if the LaTeX text is
%	long or if having "\tex[]...{}" appear all over your picture clutters
%	things up too much.
%
%     + Replacement (method 2): in your LaTeX source specify how each piece
%       of postscript text should be replaced:
%
%	  \psfrag{name}[posn][psposn][scale][rot]{LaTeX text}
%
%       The "name" argument is the postscript text to replace.  Make the
%       name alphanumeric and short (don't use braces, backslashes etc!).
%
%	All the \psfrag calls that apply to a particular postscript file
%	should immediately precede the file's \epsfbox or \special.
%	The whole thing should be enclosed in a psfrags environment
%	(this environment simply delimits the scope of the fragments
%	defined with \psfrag, so any enclosing environment (like figure etc)
%	will do instead).
%
%	Example: in a drawing program like xfig, you place the text
%
%		xy
%
%	at a particular point.  In the LaTeX source, before the ps file
%	is included, the call
%
%	  \psfrag{xy}[t]{The sum is $x + y$.}
%
%	will result in "xy" being replaced by the given LaTeX.
%
%   - There are two ways to include the postscript file:
%
%     + \epsfbox: you can use \epsfbox in the usual way (together with its
%	usual scaling options).
%
%     + \special: if you insist on directly calling \special yourself,
%       then you should call the macro \psfragspecial instead:
%
%         \psfragspecial{psfile}{hscale}{vscale}{hoffset}{voffset}{otherArgs}
%
%       (eg: \psfragspecial{example.ps}{80}{80}{23}{-10}{})
%
%       This \inputs the fragment file (<psfile> + "frag") if it exists,
%	and then it does a normal \special by concatenating the arguments.
%	The first five arguments are exactly the arguments to dvips'
%	\special ([hv]scale are in percent, and [hv]offset are in bpoints).
%	Any extra \special arguments can be passed in using otherArgs.
%
%   - Postscript text that is replaced (or starts with "\tex") will not be
%     shown when the dvi file is printed with dvips.  For debugging purposes
%     you may wish to still show the replaced postscript text.  Two macros
%     enable and disable showing of replaced postscript text:
%
%	   \psfragshowall     - show all postscript text
%	   \psfragshowdefault - don't show postscript text that is replaced
%
%     Each declaration stays in effect until the next.  The default is
%     \psfragshowdefault.
%
% Position options:
%
%   The \tex "macro" and \psfrag macro take four optional positioning
%   arguments:
%
%	In postscript:    \tex[posn][psposn][scale][rot]{LaTeX text}
%	In LaTeX source:  \psfrag{name}[posn][psposn][scale][rot]{LaTeX text}
%
%   Usually you won't specify arguments 3 & 4 (scale and rot), so you
%   will call the macros as
%
%	In postscript:    \tex[posn][psposn]{LaTeX text}
%	In LaTeX source:  \psfrag{name}[posn][psposn]{LaTeX text}
%
%   The first two positioning arguments specify how the bounding box of
%   the LaTeX text and bounding box of the postscript text line up.
%   By default, the bottom-left corner of the LaTeX text is placed at the
%   bottom-left corner of the postscript text:
%
%    <posn>   - LaTeX text reference point.  Up to two letters from the set
%	        {tblr} (as per LaTeX's \makebox position argument).
%	        Specifies one of 9 anchor points for the LaTeX text
%	        (eg: [tl] top left, [t] middle top, [] overall center etc).
%	        Default is [bl].
%
%    <psposn> - Where the LaTeX text's reference point is attached to the
%	        PostScript text.  Up to two letters from the set {tblr}.
%	        Default is [bl].
%
%   The LaTeX text may be optionally scaled and rotated about its reference
%   point:
%
%    <scale>  - LaTeX text size scale (default 1).  It's best if you use font
%	        size changes in the LaTeX text rather than scale, but you can
%               use the scale to tweak its size.  Default is [1].  Note: if
%		you specify an empty scale ("[]") or an invalid number (eg:
%		"[1.2.3]") you will get an error when the final postscript
%		file is printed (LaTeX and dvips won't complain).
%
%    <rotn>   - Extra rotation of LaTeX text about its reference point in
%	        degrees.  Nominal rotation of LaTeX text matches the postscript
%	        text that it is replacing.  The total rotation is the nominal
%	        rotation plus <rotn>.  Default is [0].  Note: if you specify
%		an empty rotn ("[]") or an invalid number (eg: "[1.2.3]")
%		you will get an error when the final postscript file is
%		printed (LaTeX and dvips won't complain).
%
% Example:
%
%   - A typical figure might look like:
%
%	\begin{figure}
%	\begin{center}
%	\begin{psfrags}
%	    \psfrag{u}[b][tr]{$u = 1 + \gamma$}
%	    \psfrag{y}[]{$\hat{y}$}
%	    \psfrag{z}[][]{output $z$}
%	    \epsfxsize=4in\leavevmode\epsfbox{example.ps}
%	\end{psfrags}
%	\end{center}
%	\caption{This is an example.}
%	\end{figure}
%
%     This replaces the postscript text "u" with $u = 1 + \gamma$.  The
%     middle-bottom of $u = 1 + \gamma$ is placed at the top-right of "u".
%     Similarly, the overall middle of $\hat{y}$ is placed at the bottom
%     left of the postscript text "y" (the default for psposn), and the
%     overall middle of $z$ is placed at the overall middle of the postscript
%     text "z".  The postscript file is centered with an x width of 4 inches.
%
%   - Embedded replacements can be performed in matlab (for example) with:
%
%	t = 0:.1:10;
%	plot(t, sin(t));
%	title('\tex[b][b]{Plot of $\sin(t)$}');
%	xlabel('\tex[t][t]{$t$}');
%	ylabel('\tex[b][b]{$\sin(t)$}');
%	text(t(30), sin(t(30)), 'p1');
%	text(t(60), sin(t(60)), 'p2');
%       % you might use some different local .m function for
%       % dumping an eps file:
%	special('example');
%
%     The middle-bottoms of the title and y axis label are aligned, as well
%     as the middle-top of the x axis label.  A suitable source file is:
%
%	\documentstyle[12pt,epsf,psfrag]{article}
%	\begin{document}
%	
%	This is a test.
%	\unitlength=1in
%
%	\begin{psfrags}
%	    \psfrag{p1}{\begin{picture}(0,0)
%		    \put(0.25, 0.1){\makebox(0,0)[l]{$\sin(t)$}}
%		    \put(0.2, 0.1){\vector(-2,-1){0.2}}
%		\end{picture}}
%	    \psfrag{p2}{\begin{picture}(0,0)
%		    \put(0,0){\circle*{0.05}}
%		\end{picture}}
%	    \epsfbox{example.ps}
%	\end{psfrags}
%
%	\end{document}
%
%     This replaces "p1" with a picture that includes a vector and some
%     text, and "p2" with a small circle.
%
%     (Note that matlab shifts text shown with text() up by 2.28 points
%     (4 * 0.57) relative to plot(), so you should use the command
%
%	ps2psfrag -dy -2.28 example.ps
%
%     to create the example.psfrag file: otherwise the circle and vector
%     above won't quite line up with the plotted curve.)
%
% Bugs:
%
%   - Everything relies on the program generating the postscript to use a
%     single postscript "show" for each piece of text displayed.  If this
%     program splits strings into lots of smaller shows, then try mono-spaced
%     fonts, and shorter strings.  If this program strokes out the characters
%     or uses other methods to draw text then you are SOL.
%
%   - The postscript operators ashow, widthshow, awidthshow, and kshow are
%     treated as simple shows by ps2psfrag.  Therefore, the postscript
%     bounding box computed by ps2psfrag might be wrong.  The symptom
%     will be slight errors in the positioning of the LaTeX text.  For
%     example, if a string is "stretched out" in postscript using ashow,
%     ps2psfrag will think the string is shorter than it really is.  If the
%     LaTeX text is aligned with the right edge of the postscript text, then
%     the LaTeX text will appear slightly to the left of where the postscript
%     text really ends.
%
%     This is not a problem with all postscript that psfrag has been tested
%     with: matlab, xfig, and idraw use show; freehand uses awidthshow but
%     with no character size and positions offsets (so it's equivalent to
%     a regular show).  Therefore, ps2psfrag's simplistic handling of the
%     other show operators is unlikely to cause any problems.
%
%     (Note that show operators that show text that isn't being replaced are
%      not perturbed in any way.)
%
%   - The LaTeX fragments always appear on top of the postscript graphics.
%     Even if part of the original postscript text was covered by postscript
%     graphics, the LaTeX fragment will be on top.
%
%   - If the first thing in a LaTeX document is a float (eg: figure) the
%     preamble \special{}s in psfrag.sty don't make it into the dvi file.
%     This causes everything to break: you will see a wierd errors from
%     ghostscript or your print daemon.  The solution is to make sure that
%     you always have something (even an empty box) between your
%     \begin{document} and your first float (eg: figure).
%
% Revision History:
%   20-Sep-92   Craig Barratt	Released version 1.1.
%   13-Sep-92   Craig Barratt	Added support for ashow, widthshow, awidthshow,
%				and kshow.
%   29-Feb-92   Craig Barratt	Initial version.
%    1-Jun-92   Craig Barratt	Released version 1.0.
%
% Send comments and bugs to Craig Barratt (craig@isl.stanford.edu)
%

%
% Redefine the show operators for specials.  We have to redefine these
% so that postscript text that is being replaced by LaTeX is removed
% from the final output.  Literal fragments (starting with \tex) aren't
% shown, and any string in the PsFragNoShowStrings array isn't shown.
% This array is augmented each time \PsFragShowString is called, and
% reset when the PSFragmentLocs environment begins.
%
\special{!
    /PsFragDict 20 dict def
    PsFragDict begin
	% decide if string is being replaced (string --> boolean)
	/PsFragCheckShow {
	    PsFragNewShow {
		/s exch def s (\string\\tex) anchorsearch { pop pop false }
		{
		    pop /showit true def
		    PsFragNoShowStrings { s eq {/showit false def} if} forall
		    showit
		} ifelse
	    } { pop true } ifelse
	} bind def
	% instead of a show, move currentpoint to end of text; also
	% does npops of stack (string npops --> -)
	/PsFragMoveShow {
	    exch stringwidth pop 0 rmoveto {pop} repeat
	} bind def
	% list of strings not to show
	/PsFragNoShowStrings [] def
	% when true the new show is enabled
	/PsFragNewShow true def
    end
    %
    % Redefine each show operator so that it doesn't show the
    % string if it's a string that is being replaced; we simply do
    % a moveto the end of the string, and pop off the other arguments.
    % Otherwise, we call the actual show operator.
    %
    /show       { PsFragDict begin dup PsFragCheckShow
			{show}       {0 PsFragMoveShow} ifelse end} bind def
    /ashow      { PsFragDict begin dup PsFragCheckShow
			{ashow}      {2 PsFragMoveShow} ifelse end} bind def
    /kshow      { PsFragDict begin dup PsFragCheckShow
			{kshow}      {1 PsFragMoveShow} ifelse end} bind def
    /widthshow  { PsFragDict begin dup PsFragCheckShow
			{widthshow}  {3 PsFragMoveShow} ifelse end} bind def
    /awidthshow { PsFragDict begin dup PsFragCheckShow
			{awidthshow} {5 PsFragMoveShow} ifelse end} bind def
}

%
% The postscript show operator is redefined above to not show text that is
% being replaced by LaTeX fragments.  These macros allow the user to change
% the show behavior:
%
%   \psfragshowall     - show all text (for debugging etc)
%   \psfragshowdefault - don't show text that is being replaced
%
% Each declaration stays in effect until the next.
%
\def\psfragshowall{\def\@psfragshowstate{false}}
\def\psfragshowdefault{\def\@psfragshowstate{true}}
\psfragshowdefault

%
% various dimensions that we will use for our layout calculations
%
\newdimen\psfragx
\newdimen\psfragy
\newdimen\psfragxhalfsz
\newdimen\psfragyhalfsz
\newdimen\psfragangle
\newdimen\psfragangledim

%
% Define a fragment:
%
%   \psfrag{name}[posn][psposn][scale][rot]{text}
%
% See documentation above.
%
% All this macro does is save away its arguments for later use by \PsFragInfo
% We don't give a multiple-defined warning for an empty <name> since an
% empty name is used for the "\tex..." hook.
%
\def\psfrag#1{\@ifnextchar [{\@psfraga#1}{\@psfrag#1[bl][bl][1][0]}}
\def\@psfraga#1[#2]{\@ifnextchar [{\@psfragb#1[#2]}{\@psfrag#1[#2][bl][1][0]}}
\def\@psfragb#1[#2][#3]{\@ifnextchar [{\@psfragc#1[#2][#3]}{\@psfrag#1[#2][#3][1][0]}}
\def\@psfragc#1[#2][#3][#4]{\@ifnextchar [{\@psfrag#1[#2][#3][#4]}{\@psfrag#1[#2][#3][#4][0]}}

\long\def\@psfrag#1[#2][#3][#4][#5]#6{%
    \@psfragcheckepsf%
    \@ifundefined{psfg@#1}{}{\ifx #1\@empty\else \@warning{Replacement
	for PostScript Fragment `#1' on page \thepage \space redefined}\fi}%
    \@namedef{psfg@#1}{{#2}{#3}{#4}{#5}}%
    \@namedef{psfgr@#1}{#6}\ignorespaces}

%
% This environment does nothing other than delimit the scope of the
% ps fragments saved away by \psfrag.  Using this environment is unnecessary
% if something else (eg, \begin{figure}...\end{figure}) already encloses 
% the fragments.
%
\newenvironment{psfrags}{\ignorespaces}{\ignorespaces}

%
% This environment is used in the file generated by ps2psfrag.
% It's just a zero-sized picture (which MUST be at the same
% location as the postscript file's \special)
% 
\newenvironment{PSFragmentLocs}{%
    % reset the list of no show strings
    \special{ps:SDict /PsFragDict get begin /PsFragNoShowStrings [] def %
	/PsFragNewShow \@psfragshowstate \space def end}%
    \begin{picture}(0,0)(0,0)%
}{%
    \end{picture}%
}

%
% A check that sees if the old style epsf.sty is being used.
% Also, if epsf doesn't appear to have been loaded, then we
% create the dimens that we need from epsf.sty
%
\def\@psfragcheckepsf{%
    \expandafter\ifx\csname pspoints\endcsname\relax%
	% No epsf.sty, so the user must be using a manual \special.  Create
	% some dimens that we need (these are usually defined in epsf.sty)
	\newdimen\epsfhbpsize
	\newdimen\epsfvbpsize
	\newdimen\pspoints
	\pspoints=1bp
    \else
	\expandafter\ifx\csname epsfhbpsize\endcsname\relax%
	    % serious bummer, we have the old epsf.sty
	    \errmessage{You are using an old epsf.sty with psfrag.sty. Psfrag will not work}
	\else
	    % good, we have the new epsf.sty
	\fi
    \fi
    % only do this once!
    \def\@psfragcheckepsf{}%
}

%
% Allow the user to manually call special.  We have to know the offsets,
% scales, and filename.
%
%   \psfragspecial{filename}{hscale}{vscale}{hoffset}{voffset}{otherArgs}
%
\newread\psfragfilein
\def\psfragspecial#1#2#3#4#5#6{%
    \def\epsfllx{0}\def\epsflly{0}%
    \epsfhbpsize=#2\pspoints \divide \epsfhbpsize by 100%
    \epsfvbpsize=#3\pspoints \divide \epsfvbpsize by 100%
    \begin{picture}(0,0)(0,0)%
	\openin\psfragfilein=#1frag
	\ifeof\psfragfilein%
	    \put(0,0){\special{PSfile=#1 hscale=#2 vscale=#3 hoffset=#4 %
		voffset=#5 #6}}%
	\else%
	     \closein\psfragfilein%
	     %\put(0.6,-0.6){\input{#1frag}}
	     \def\PsFragSpecialArgs{PSfile=#1 hscale=#2 vscale=#3 #6}%
	     \@killglue\raise#5\pspoints\hbox to 0pt{\kern #4\pspoints
		 \input{#1frag}\hss}%
	\fi%
    \end{picture}
}


%
% if this fragment is being replaced, we augment the list of no show
% strings, so that the original postscript text doesn't show up when
% it is included
%
\def\PsFragShowString#1{\@ifundefined{psfg@#1}{}{%
    \def\psfragtemp{#1}%
    \ifx\psfragtemp\@empty\else%
	% augment list of no show strings (this is o(n), so I'm sure
	% there is a better way!)
	\put(0,0){\special{ps:SDict /PsFragDict get begin %
	    /PsFragNoShowStrings [PsFragNoShowStrings aload pop (#1)] def %
	    end}}%
    \fi%
}}

%
% This does all the work:
%
%   \PsFragInfo{text}{x}{y}{bbhx}{bbhy}{bbvx}{bbvy}{rotn}
%
% <text> is the argument of the postscript show operator.
% <x> and <y> are the absolute coords (pts) of the text's lower-left corner.
% <bbhx> and <bbhy> are the dx and dy of the base of the text's bbox.
% <bbvx> and <bbvy> are the dx and dy of the height of the text's bbox.
% <rotn> is the rotation in degrees of the text.
%
% Note: this macro assumes that it is inside a picture environment!
%
\def\PsFragInfo#1#2#3#4#5#6#7#8{\@ifundefined{psfg@#1}{}{%
	\@psfragcheckepsf%
	\edef\@tempa{\@nameuse{psfg@#1}}
	\edef\@fragboxposn{\expandafter\@car\@tempa\@nil}%
        \edef\@tempa{\expandafter\@cdr\@tempa\@nil}%
	\edef\@fragtextposn{\expandafter\@car\@tempa\@nil}%
        \edef\@tempa{\expandafter\@cdr\@tempa\@nil}%
	\edef\@fragscale{\expandafter\@car\@tempa\@nil}%
        \edef\@fragangle{\expandafter\@cdr\@tempa\@nil}%
	% compute the total angle (fake it as a dimension for now)
	\psfragangledim=10sp
	\psfragangle=#8\psfragangledim
	\advance\psfragangle by \@fragangle\psfragangledim
	% put the fragment at the middle of the postscript text box
	\psfragxhalfsz=0.5\epsfhbpsize
	\psfragyhalfsz=0.5\epsfvbpsize
	\psfragx=#2\epsfhbpsize
	\advance\psfragx by -\epsfllx\epsfhbpsize
	\advance\psfragx by #4\psfragxhalfsz
	\advance\psfragx by #6\psfragxhalfsz
	\psfragy=#3\epsfvbpsize
	\advance\psfragy by -\epsflly\epsfvbpsize
	\advance\psfragy by #5\psfragyhalfsz
	\advance\psfragy by #7\psfragyhalfsz
	% now adjust the fragment position based on the positioning args
	%
        % Something like this should work, but it doesn't (how to I expand
	% the macro into tokens??)
	%      \@tfor \@tempa :=\@fragtextposn\do {
	%
	% Since I'm TeX-illiterate, manually suck off the first two chars
	% and use them.  (The xx is in case \@fragtextposn is empty...)
        \edef\@fragposa{\expandafter\@car\@fragtextposn xx\@nil}%
	\edef\@fragposb{\expandafter\@cdr\@fragtextposn xx\@nil}%
        \edef\@fragposb{\expandafter\@car\@fragposb\@nil}%
        \@tfor \@tempa := \@fragposa\@fragposb
	\do {
	    \if\@tempa l
		\advance\psfragx by -#4\psfragxhalfsz
		\advance\psfragy by -#5\psfragyhalfsz
	    \fi
	    \if\@tempa r
		\advance\psfragx by  #4\psfragxhalfsz
		\advance\psfragy by  #5\psfragyhalfsz
	    \fi
	    \if\@tempa b
		\advance\psfragx by -#6\psfragxhalfsz
		\advance\psfragy by -#7\psfragyhalfsz
	    \fi
	    \if\@tempa t
		\advance\psfragx by  #6\psfragxhalfsz
		\advance\psfragy by  #7\psfragyhalfsz
	    \fi
        }
	% see comments about about why I have to do this for \makebox()[]{}
        \edef\@fragposa{\expandafter\@car\@fragboxposn xx\@nil}%
	\edef\@fragposb{\expandafter\@cdr\@fragboxposn xx\@nil}%
        \edef\@fragposb{\expandafter\@car\@fragposb\@nil}%
	%
	% now put it down
	\@killglue\raise\psfragy\hbox to \z@{\kern 1.0\psfragx{%
	    \ifdim\@fragscale\pspoints=0\pspoints \def\@fragscale{1} \fi
	    \ifdim\psfragangle=0sp \ifdim\@fragscale\pspoints=1\pspoints
		\makebox(0,0)[\@fragposa\@fragposb]{\@nameuse{psfgr@#1}}%
	    \else
		% enclose the box in some specials that do the scale
		% (courtesy of rotate.tex)
		\special{ps:gsave currentpoint currentpoint translate
			\@fragscale \space \@fragscale \space scale
			neg exch neg exch translate}%
		\makebox(0,0)[\@fragposa\@fragposb]{\@nameuse{psfgr@#1}}%
		\special{ps:currentpoint grestore moveto}%
	    \fi\else
		% enclose the box in some specials that do the scale
		% and rotate (courtesy of rotate.tex).  First round the
		% angle to nearest 0.01 degree.
		\multiply\psfragangle by 100%
		\ifdim\psfragangle < 0\psfragangledim%
		    %\advance\psfragangle by -0.5\psfragangledim%
		\else
		    \advance\psfragangle by 0.5\psfragangledim%
		\fi
		\divide\psfragangle by \psfragangledim%
		\special{ps:gsave currentpoint currentpoint translate
			\number\psfragangle \space -100 div rotate
			\@fragscale \space \@fragscale \space scale
			neg exch neg exch translate}%
		\makebox(0,0)[\@fragposa\@fragposb]{\@nameuse{psfgr@#1}}%
		\special{ps:currentpoint grestore moveto}%
	    \fi%
	}\hss}\ignorespaces}}
